import json
import math
import shutil
from datetime import datetime
import os
import subprocess
import time
import csv
import re


def get_environment_state():
    # adb 获取当前cpu占用前10的进程
    command = f"adb shell top -n 1 -m 10|awk 'NR>5{{print $9,$10,$12}}'"
    process_list = subprocess.check_output(command, shell=True, text=True, stderr=subprocess.STDOUT).strip()
    process_list = process_list.split("\n")
    process_list = process_list[1:]
    return process_list
def get_pid(process_name):
    try:
        command = f"adb shell ps -A|grep -i {process_name}|awk 'NR==1{{print $2}}'"
        pid = subprocess.check_output(command, shell=True, text=True, stderr=subprocess.STDOUT).strip()
        return pid
    except subprocess.CalledProcessError as e:
        print(e)
        return None


def get_cpu_usage(pid):
    try:

        command = f"adb shell COLUMNS=256 top -b -n 1 -p {pid}"
        lines = subprocess.check_output(command, shell=True)
        # 获取第四行内容
        result = lines.decode("utf-8").split("\n")[5]
        infos = re.split(" +", result)
        res_usage = infos[6].strip()
        cpu_usage = infos[9].strip()
        info = {'cpu_usage': cpu_usage, 'res_usage': res_usage}
        return info
    except Exception as e:
        print(e)
        return None


def get_gpu_usage(package_name):
    try:
        command = f"adb shell cat /sys/class/kgsl/kgsl-3d0/gpu_busy_percentage"
        gpu_percent = subprocess.check_output(command, shell=True).decode()
        # 获取第四行内容
        return gpu_percent.strip()
    except Exception as e:
        print(e)
        return None


def get_frame_states(package_name, window_name, name, record):
    try:
        # 通过dumpsys gfxinfo 获取目标进程指定window的信息
        command = f"adb shell dumpsys gfxinfo {package_name} {package_name}:{window_name}"
        lines = subprocess.check_output(command, shell=True).decode()

        frameFilePath = f"{name}frames.csv"
        # 判断文件是否存在 不存在就创建文件
        mode = "w"
        if os.path.exists(frameFilePath):
            mode = "a"

        with open(f"{name}frames.csv", mode, newline="") as frameFile:

            fieldnames = {"Draw", "Prepare", "Process", "Execute","Total","ExtCoastFrame"}
            writer = csv.DictWriter(frameFile, fieldnames=fieldnames)

            if mode.__eq__("w"):
                writer.writeheader()

            fps = 0

            inFrameDetail = False
            for line in lines.split("\n"):
                # 判断是否是Total frames rendered 开头的那一行
                if line.startswith("Total frames rendered"):
                    # 用：分割获取
                    total_frames = line.split(":")[1].strip()
                # 判断是否是Janky frames 开头的那一行
                elif line.startswith("Janky frames"):
                    janky_datas = line.split(":")[1].strip().split(" ")
                    janky_frames = janky_datas[0].strip()
                    janky_percnt = janky_datas[1].strip()

                elif line.strip().startswith("Draw	Prepare	Process	Execute"):
                    # 退出概览数据处理
                    inFrameDetail = True
                    coast_vsync_count = 0
                    frame_count = 0
                elif inFrameDetail and line.strip().__eq__(""):
                    inFrameDetail = False
                elif inFrameDetail:
                    # Draw	Prepare	Process	Execute
                    frame_count += 1
                    datas = re.split("\t", line.strip())
                    coastTime = float(datas[0]) + float(datas[1]) + float(datas[2]) + float(datas[3])
                    # 计算当前帧的耗时占用几个VSync 信号周期 向上取整
                    cost_vsync = math.floor(coastTime / 16.67)
                    coast_vsync_count += cost_vsync
                    # 保留1位小数
                    fps = round(60 * frame_count / (frame_count + coast_vsync_count), 1)
                    # 写入文件
                    if record == 'True':
                        row = {"Draw": float(datas[0]), "Prepare": float(datas[1]), "Process": float(datas[2]),
                               "Execute": float(datas[3]),"Total":float(coastTime),"ExtCoastFrame":int(cost_vsync)}
                        writer.writerow(row)

        infos = {'fps': fps, 'total_frames': total_frames, 'janky_frames': janky_frames}
        # 计算dumpsys gfxinfo 结果中vsync 的总次数
        return infos
    except Exception as e:
        print(e)
        return None


def calculate_max_min_average(path):
    #打开path路径文件
    print(path)

    with open(f"{path}", 'r') as f:
        # 读取文件内容

        lines = f.readlines()
        print(lines)
        counter = 0

        max_cpu = float(0)
        min_cpu = float(1000)
        average_cpu = float(0)

        max_fps=float(0)
        average_fps=float(0)
        min_fps=float(0)

        total_frames = 0
        janky_frames = 0
        # 遍历文件内容
        fps_zero_count=0
        cpu_zero_count=0
        total_time = 0
        # 遍历文件内容
        # 对cpu 获取最大值 最小值
        first_line = True
        for line in lines:
            if first_line:
                first_line = False
                continue

            # 获取每一行中的数据
            datas = re.split(",", line.strip())
            # 获取数组中 cpu数据
            cpu = float(datas[3])
            if 0< max_cpu < cpu:
                max_cpu = cpu

            if 0 < cpu <min_cpu:
                min_cpu = cpu

            # fps 数据
            fps = float(datas[5])
            if 0 <max_fps < fps:
                max_fps = fps

            if min_fps > fps > 0.0:
                min_fps = fps

        total_fps = 0
        total_fps_count = 0
        total_cpu=0
        total_cpu_count = 0
        first_line = True
        # 获取平均值
        for line in lines:
            if first_line:
                first_line = False
                continue
            # 获取每一行中的数据
            datas = re.split(",", line.strip())
            # 获取数组中 cpu数据
            cpu = float(datas[3])
            total_cpu +=cpu
            total_cpu_count+=1


            fps = float(datas[5])
            if fps !=0.0:
                total_fps+=fps
                total_fps_count+=1

            # 计算绘制帧的总数
            total_frames = total_frames + int(datas[6])
            # 计算janky帧的总数
            janky_frames = janky_frames + int(datas[7])

        average_cpu = total_cpu/total_cpu_count
        average_fps = total_fps/total_fps_count

        print("totalFps"+total_fps +" totalFps Count "+total_fps_count)



        return {
            "max_cpu": max_cpu,
            "min_cpu": min_cpu,
            "average_cpu": average_cpu,
            "max_fps": max_fps,
            "min_fps": min_fps,
            "average_fps": average_fps,
            "total_frames": total_frames,
            "janky_frames": janky_frames}


def clearHistory(process):
    reportDirRoot = f"report/{process}"
    if os.path.exists(reportDirRoot) is False:
        return
    else:
        shutil.rmtree(reportDirRoot)


def createReport(path):
    with open(f"{path}.csv", "r") as reportFile:
        reader = csv.DictReader(reportFile)
        counter = 0
        max_cpu = float(0)
        min_cpu = float(100)
        average_cpu = float(0)

        max_fps = float(0)
        average_fps = float(0)
        min_fps = float(60)

        total_frames = 0
        janky_frames = 0
        # 遍历文件内容
        total_fps=0
        total_fps_count=0
        total_cpu=0
        total_cpu_count=0
        total_time = 0
        # 遍历文件内容
        for row in reader:
            print(row)
            counter += 1
            if counter == 1:
                continue

            # 获取数组中 cpu数据
            cpu_percent = str(row["Cpu"]).split(" ")[0]
            cpu = float(cpu_percent)
            if cpu > max_cpu:
                max_cpu = cpu

            if 0 <cpu < min_cpu:
                min_cpu = cpu
            # 计算当前获取到的所有cpu平均值
            average_cpu = float(((counter - 1) * average_cpu + cpu) / counter)
            # 计算当前获取到的所有fps平均值
            fps = float(row["FPS"])
            if fps > max_fps:
                max_fps = fps

            if 0 <fps < min_fps :
                min_fps = fps
            # 计算当前获取到的所有fps平均值
            if fps !=0.0:
                total_fps+=fps
                total_fps_count+=1

            total_cpu+=cpu
            total_cpu_count+=1

            # 计算绘制帧的总数
            total_frames = total_frames + int(row["Total_Frames"])

            # 计算janky帧的总数
            janky_frames = janky_frames + int(row["Janky"])

        average_cpu = total_cpu/total_cpu_count
        average_fps = total_fps/total_fps_count

        data =  {
            "max_cpu": max_cpu,
            "min_cpu": min_cpu,
            "average_cpu": average_cpu,
            "max_fps": max_fps,
            "min_fps": min_fps,
            "average_fps": average_fps,
            "total_frames": total_frames,
            "janky_frames": janky_frames}
        print(data)

def createFrameReport(path):
    with open(f"{path}.csv","r") as frameFile:
        reader = csv.DictReader(frameFile)
        max_lost_frame_count=0
        lost_count = 0
        for row in reader:
            dictionary:dict = eval(str(row))
            coast = int(dictionary["ExtCoastFrame"])
            if  coast > 0 and coast > lost_count:
                lost_count = coast
            else:
                if max_lost_frame_count < lost_count:
                    max_lost_frame_count = lost_count
                lost_count = 0

        print("max lost frame count =",max_lost_frame_count)


def main():
    # 读取config.json 的内容
    current_dir = os.path.dirname(os.path.abspath(__file__))
    with open(f"{current_dir}/config.json", "r") as f:
        config = json.load(f)
        if config is None or config.get("packageName") is None or config.get("windowName") is None:
            print("config.json 配置文件错误")
            exit(-1)

        process_name = config["packageName"]
        window_name = config["windowName"]
        need_record = config["recordFrames"]


    process_dir = process_name.split('.')[-1]

    reportDir = f"report/{process_dir}"

    # 获取 clearHistory 参数
    needRemoveHistory = bool(config.get("clearHistory")=="True")
    print(config.get("clearHistory"))
    print(needRemoveHistory)
    if needRemoveHistory:
        clearHistory(process_dir)

    # 获取当前时间戳
    current_time = time.time()
    millis = int(current_time * 1000)
    # 转为时分秒
    current_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(current_time))

    # 获取当前时间戳
    current_time = time.time()
    # 以包名的最后一段 命名报告文件


    pid = ""
    while pid == "":
        pid = get_pid(process_name)

    print(f"获取目标进程id {pid}")

    # 获取当前时间戳
    current_time = time.time()
    millis = int(current_time * 1000)
    # 转为时分秒

    reportName = datetime.now().strftime("%Y%m%d%H%M%S")
    if not os.path.exists(f"{reportDir}"):
        os.makedirs(f"{reportDir}")

    path = reportDir + "/" + reportName
    coast: int = 0
    with open(f"{path}.csv", "w", newline="") as reportFile:
        fieldnames = ["Index", "Millis", "Gpu", "Cpu", "Process_Res_Usage", "FPS", "Total_Frames",
                      "Janky","Environment_State"]
        writer = csv.DictWriter(reportFile, fieldnames=fieldnames)
        writer.writeheader()
        record_index = -1

        while True:
            try:
                # reset data
                command = f"adb shell dumpsys gfxinfo {process_name} {process_name}:{window_name} reset"
                subprocess.check_output(command, shell=True)
                # 计算 耗时 并进行矫正
                finish_time = time.time()
                finish_millis = (finish_time * 1000)
                coast = finish_millis - millis
                # 获取当前时间戳
                if coast<1000:
                    time.sleep((1000 - coast) / 1000)

                current_time = time.time()
                millis = int(current_time * 1000)
                # 转为时分秒
                current_time = time.strftime("%H:%M:%S", time.localtime(current_time))
                # 先记录当前系统环境情况
                env = get_environment_state()

                # 获取当前进程的CPU使用率
                cpu_info = get_cpu_usage(pid)
                gpu_percent = get_gpu_usage(process_name)
                frame_states = get_frame_states(process_name, window_name, path, need_record)
                if record_index == -1:
                    record_index += 1
                    continue

                record_index += 1
                row ={}
                row["Millis"] = millis
                if cpu_info:
                    row["Cpu"] = cpu_info['cpu_usage']+" %"
                    row["Process_Res_Usage"] = cpu_info['res_usage']


                if frame_states:
                    row["FPS"]=frame_states['fps']
                    row["Janky"]= frame_states['janky_frames']
                    row["Total_Frames"]= frame_states['total_frames']

                if gpu_percent:
                    row["Gpu"]= gpu_percent
                # 判断cpu_info 和frame_states 同时为none
                if cpu_info is None or frame_states is None:
                    continue

                # 如果当前的帧率较低 <56 记录环境状态
                if frame_states['fps'] < 56:
                    row["Environment_State"]=env
                writer.writerow(row)
                print(row)
                # # 每1000ms获取一次
                # time.sleep((1000-(finish_millis-millis))/1000)
                pass
            except KeyboardInterrupt:
                print("采集结束，开始统计数据")
                break

            # 读取文件内容
    createReport(path)
    createFrameReport(f"{path}frames")


if __name__ == "__main__":
    main()
